home *** CD-ROM | disk | FTP | other *** search
- /* origonal from norbert schelenkar's stdio */
- /* eff hacks ++jrb */
-
- #include <ctype.h>
- #include <errno.h>
- #include <limits.h>
- #include <stdlib.h>
-
- /* defines to avoid long muls on a lowly 68k */
- #define _TEN_MUL(X) ((((X) << 2) + (X)) << 1)
- #define _BASEMUL(B, X) \
- (((B) == 10) ? _TEN_MUL((X)) : (((B) == 16) ? ((X) << 4) : ((X) << 3)))
-
- unsigned long int strtoul(nptr, endptr, base)
- register _CONST char *nptr;
- char **endptr;
- int base;
- {
- register short c;
- unsigned long result = 0L;
- unsigned long limit;
- short negative = 0;
- short overflow = 0;
- short digit;
-
- while ((c = *nptr) && isspace(c)) /* skip leading white space */
- nptr++;
- if ((c = *nptr) == '+' || c == '-') { /* handle signs */
- negative = (c == '-');
- nptr++;
- }
- if (base == 0) { /* determine base if unknown */
- base = 10;
- if (*nptr == '0') {
- base = 8;
- nptr++;
- if ((c = *nptr) == 'x' || c == 'X') {
- base = 16;
- nptr++;
- }
- }
- }
- else
- if (base == 16 && *nptr == '0') { /* discard 0x/0X prefix if hex */
- nptr++;
- if ((c = *nptr == 'x') || c == 'X')
- nptr++;
- }
-
- limit = (base == 10) ? ULONG_MAX/10L : /* ensure no overflow */
- ((base == 8) ? ULONG_MAX/8L : ULONG_MAX/16L);
-
- nptr--; /* convert the number */
- while (c = *++nptr) {
- if (isdigit(c))
- digit = c - '0';
- else
- digit = c - (isupper(c) ? 'A' : 'a') + 10;
- if (digit < 0 || digit >= base)
- break;
- if (result > limit)
- overflow = 1;
- if (!overflow) {
- result = _BASEMUL(base, result);
- if (digit > ULONG_MAX - result)
- overflow = 1;
- else
- result += digit;
- }
- }
- if (negative && !overflow) /* BIZARRE, but ANSI says we should do this! */
- result = 0L - result;
- if (overflow) {
- errno = ERANGE;
- result = ULONG_MAX;
- }
-
- if (endptr != NULL) /* point at tail */
- *endptr = (char *)nptr;
- return result;
- }
-